

.text
.global _start


_start:
	b reset      /* vector 0: reset */
	b do_undf    /* vector 4: undefined  */

do_undf:
	/* sp_und 未设置 */
	ldr sp, =0x34000000 /* 64M SDRAM 最高地址**/

	/* 保存现场 */
	stmdb sp!, {r0-r12, lr}

	/* 处理现场 undefined */
	mrs r0, cpsr
	ldr r1, =undf_string 
	bl print_execption

	/* 恢复现场 */
	ldmia sp!, {r0-r12, pc}^  /* ^ 会把spsr 的值恢复到cpsr 中 */

undf_string:
	.string "undefined instruction exception"

reset:
	/* 关闭看门口 */
	LDR  r0, =0x53000000;
	LDR  r1, =0;
	STR  r1, [r0];

	/* 设置MPLL, FCLK:HCLK:PCLK=400M:100M:50M 频率比 */

	/*
		LOCKTIME(0x4C000000)=0xFFFFFFFF
	*/
	LDR r0, =0x4C000000
	LDR r1, =0xFFFFFFFF
	STR r1, [r0]


	/*
		CLKDIVN(0x4C000014)=0x5, tFCLK:tHCLK:tPCLK=1:4:8 周期比较
	*/
	LDR r0, =0x4C000014
	LDR r1, =0x5
	STR r1, [r0]

	/*
		设置CPU工作于异步模式
	*/
	mrc p15,0,r0,c1,c0,0
	orr r0,r0,#0xc0000000
	mcr p15,0,r0,c1,c0,0

	/*
		设置 MPLLCON(0x4C000004)= (92<<12)|(1<<4)|(1<<0)
		m = MDIV+8 = 92+8 = 100
		p = PDIV +2 = 1+2 =3
		s = SDIV = 1
		FLCK = 2*m*Fin/(p*2^s)= 2*100*12/(3*2^1)=400M		
	*/
	LDR r0, =0x4C000004
	LDR r1, =(92<<12)|(1<<4)|(1<<0)
	STR r1, [r0]

	/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
	 * 然后CPU工作于新的频率FCLK
	 */

	/*  设置栈 SP
	 * 分辨是 nand or nor 启动
	 * 写0到0地址, 再读出来
	 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
	 * 否则就是nor启动
	*/
	MOV   r1, #0;
	LDR   r0, [r1]   // 读出原来的值，用于备份
	STR   r1, [r1]   // 0地址写入0
	LDR   r2, [r1]   // 读出0地址数据到r2
	cmp   r1, r2     // r1 == r2 如果相等就是NAND 启动，
    ldr   sp, =0x40000000+4096   // 假设是nor启动
	moveq sp, #4096      //  nand 启动
	streq r0, [r1]        /* 恢复原来的值 */
	
	bl sdram_init

	/* 重定位text, rodata, data 段 整个程序 */
	bl copy2sdram   /* src, dest, len */

	/* 清除 bss 段 */
	bl clean_bss   /* start, end */

	bl urat0_init

	bl print1
	/* 故意加入一条未定义指令 */
undf_code:
	.word  0x03000000

	bl print2
/*
	1 使用相对跳转命令， B/BL
	2 重定位之前，不可以使用绝对地址，不可访问全局变量/静态变量
		         不可访问全局变量/静态变量
				 不可访问有初始值的数组
	3 重定位后，使用 ldr pc, =xxxx, 跳转到 runtime address.

	使用位置无关码，不使用绝对地址，看反汇编
 */
	// bl  main   /* BL是相对指令， 跳转后依然在 NOR/SRAM中运行 */
	ldr pc, =main /* 绝对跳转，跳到 SDRAM */

halt:
	b halt







